/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002-2006
* Sleepycat Software. All rights reserved.
*
* $Id: Tracer.java,v 1.1 2006/05/06 09:00:31 ckaestne Exp $
*/
package com.sleepycat.je.utilint;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.ByteBuffer;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.logging.Level;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.config.ConfigParam;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.log.LogEntryType;
import com.sleepycat.je.log.LogReadable;
import com.sleepycat.je.log.LogUtils;
import com.sleepycat.je.log.LoggableObject;
/**
* The Tracer generates debug messages that are sent to the java.util.Logging
* facility. There are three log handlers set up for logging -- the database
* log itself, an output file, and stdout (the "console"). By default, only
* the database file is enabled.
*/
public class Tracer implements LoggableObject, LogReadable {
/*
* Name pattern for tracing output that's been directed into a log file by
* enabling the file handler.
*/
public static final String INFO_FILES = "je.info";
/*
* Contents of a debug message.
*/
private Timestamp time;
private String msg;
/**
* Create a new debug record.
*/
public Tracer(String msg) {
this.time = getCurrentTimestamp();
this.msg = msg;
}
/**
* Create trace record that will be filled in from the log.
*/
public Tracer() {
}
/*
* Static utility methods for submitting information for logging in the
* text log file, the database log, and stdout.
*/
/**
* Logger method for recording a general message.
*/
public static void trace(Level logLevel,
EnvironmentImpl envImpl,
String msg) {
envImpl.getLogger().log(logLevel, msg);
}
/**
* Logger method for recording an exception and stacktrace.
*/
public static void trace(EnvironmentImpl envImpl,
String sourceClass,
String sourceMethod,
String msg,
Throwable t) {
/*
* Give it to the Logger, which will funnel it to stdout and/or the
* text file and/or the database log file
*/
envImpl.getLogger().logp(Level.SEVERE,
sourceClass,
sourceMethod,
msg + "\n" + Tracer.getStackTrace(t));
}
/**
* Parse a logging level config parameter, and return a more explanatory
* error message if it doesn't parse.
*/
public static Level parseLevel(EnvironmentImpl envImpl,
ConfigParam configParam)
throws DatabaseException {
Level level = null;
try {
String levelVal = envImpl.getConfigManager().get(configParam);
level = Level.parse(levelVal);
} catch (IllegalArgumentException e) {
throw new DatabaseException("Problem parsing parameter " +
configParam.getName() +
": " + e.getMessage(), e);
}
return level;
}
/*
* Helpers
*/
public String getMessage() {
return msg;
}
/**
* @return a timestamp for "now"
*/
private Timestamp getCurrentTimestamp() {
Calendar cal = Calendar.getInstance();
return new Timestamp(cal.getTime().getTime());
}
/**
* @return the stacktrace for an exception
*/
public static String getStackTrace(Throwable t) {
StringWriter s = new StringWriter();
t.printStackTrace(new PrintWriter(s));
String stackTrace = s.toString();
stackTrace = stackTrace.replaceAll("<", "<");
stackTrace = stackTrace.replaceAll(">", ">");
return stackTrace;
}
/*
* Logging support
*/
/**
* @see LoggableObject#getLogType
*/
public LogEntryType getLogType() {
return LogEntryType.LOG_TRACE;
}
/**
* @see LoggableObject#marshallOutsideWriteLatch
* Can be marshalled outside the log write latch.
*/
public boolean marshallOutsideWriteLatch() {
return true;
}
/**
* @see LoggableObject#countAsObsoleteWhenLogged
*/
public boolean countAsObsoleteWhenLogged() {
return false;
}
/**
* @see LoggableObject#postLogWork
*/
public void postLogWork(long justLoggedLsn) {
}
/**
* @see LoggableObject#getLogSize()
*/
public int getLogSize() {
return (LogUtils.getTimestampLogSize() +
LogUtils.getStringLogSize(msg));
}
/**
* @see LoggableObject#writeToLog
*/
public void writeToLog(ByteBuffer logBuffer) {
/* Load the header. */
LogUtils.writeTimestamp(logBuffer, time);
LogUtils.writeString(logBuffer, msg);
}
/**
* @see LogReadable#readFromLog
*/
public void readFromLog(ByteBuffer itemBuffer, byte entryTypeVersion) {
/* See how many we want to read direct. */
time = LogUtils.readTimestamp(itemBuffer);
msg = LogUtils.readString(itemBuffer);
}
/**
* @see LogReadable#dumpLog
*/
public void dumpLog(StringBuffer sb, boolean verbose) {
sb.append("<Dbg time=\"");
sb.append(time);
sb.append("\">");
sb.append("<msg val=\"");
sb.append(msg);
sb.append("\"/>");
sb.append("</Dbg>");
}
/**
* @see LogReadable#logEntryIsTransactional
*/
public boolean logEntryIsTransactional() {
return false;
}
/**
* @see LogReadable#getTransactionId
*/
public long getTransactionId() {
return 0;
}
public String toString() {
return (time + "/" + msg);
}
/**
* For unit tests.
*/
/**
* Just in case it's ever used as a hash key.
*/
public int hashCode() {
return toString().hashCode();
}
/**
* Override Object.equals
*/
public boolean equals(Object obj) {
/* Same instance? */
if (this == obj) {
return true;
}
/* Is it another Tracer? */
if (!(obj instanceof Tracer)) {
return false;
}
/*
* We could compare all the fields individually, but since they're all
* placed in our toString() method, we can just compare the String
* version of each offer.
*/
return (toString().equals(obj.toString()));
}
}